module ContestsHelper
  def ContestsHelper.select_random_from_array(num, arr)
    toRet = []
    num.times do
      while toRet.include?(x = rand(arr.size))
      end
      toRet << x
    end
    toRet.map{|e| arr[e]}
  end

  def ContestsHelper.choose_problems(difficulties_hash, exclude_list = nil)
    problems = Problem.find(:all)
    if exclude_list
      problems = problems.select { |p| !exclude_list.include? p }
    end
    problems = problems.sort_by { |prob| prob.contests.size }
    less_used = problems.select do |prob|
      prob.contests.size < problems.last.contests.size
    end
    can_be_reduced = true
    difficulties_hash.each_pair do |k, v|
      can_be_reduced = false if less_used.select{|p| p.difficulty == k}.size < v
    end
    less_used = problems unless can_be_reduced
    selected_problems = []
    difficulties_hash.each_pair do |k, v|
      selected_problems = selected_problems + select_random_from_array(v, less_used.select{|p| p.difficulty == k})
    end
    shuffle!(selected_problems)
  end
  
  def make_user_array(users, runs, contest)
    to_ret = []
    problems = contest.problems
    users.each do |user|
      to_push = {}
      to_push[:penalt] = 0
      to_push[:user] = user 
      to_push[:problems] = []
      to_push[:accepts] = 0
      problems.each do |problem|
        first_succ = select_first_success(problem, runs, user)
        all_unsuccessful = select_unsuccessful(problem, runs, user, first_succ)
        all_unsuccessful = all_unsuccessful.sort_by{|a| a.created_at}
        if first_succ.nil?
          if all_unsuccessful == []
            to_push[:problems] << ["-", ""]
          else
            to_push[:problems] << ["-" + all_unsuccessful.size().to_s, 
              chop_plus(calc_time(contest,all_unsuccessful.last).to_utc_offset_s.to_s)]
          end
        else
          to_push[:accepts] = to_push[:accepts] + 1
          acc_time = calc_time(contest, first_succ).to_f
          to_push[:penalt] = to_push[:penalt] + 
            (acc_time / 60.0).to_i + all_unsuccessful.size() * 20 
          if all_unsuccessful.size() != 0
            unsuc_str = all_unsuccessful.size().to_s
          else
            unsuc_str = ""
          end
          to_push[:problems] << ["+" + unsuc_str, chop_plus(acc_time.to_utc_offset_s.to_s)]
        end
      end
      to_ret << to_push
    end
    to_ret.sort_by{|t| [-t[:accepts], t[:penalt]]}
  end
  
  def contest_date(cont_date)
    cont_date.localtime.strftime "%a %d %b %Y %H:%M"
  end
  
  def chop_plus(diff)
    diff[1, diff.size]
  end
  
  private
  
  def select_first_success(problem, runs, user)
    accepts = runs.select{|r| r.problem == problem && r.status == "Accepted" && r.user == user}
    if accepts.size != 0
      accepts.sort_by{|a| a.created_at}[0]
    else
      nil
    end
  end
  
  def select_unsuccessful(problem, runs, user, first_succ)
    if(first_succ.nil?)
      unsucc = runs.select{|r| r.problem == problem && r.status != "Accepted" &&
          r.user == user}
    else
      unsucc = runs.select{|r| r.problem == problem && r.status != "Accepted" &&
          r.user == user && r.created_at < first_succ.created_at}
    end
  end
  
  def calc_time(contest, run)
    (run.created_at - contest.start_time).to_f
  end
  
  def calc_time_string(time)
    (time / 60).to_s + ":" + (time % 60).to_s
  end
  
  def ContestsHelper.shuffle!(a)
    a.size.downto(1) { |n| a.push a.delete_at(rand(n)) }
    a
  end


end
